package presentation.windows;

import java.awt.Dimension;
import java.rmi.RemoteException;
import java.util.Vector;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import javax.swing.SwingWorker;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import presentation.UIMember;
import presentation.UIPost;
import presentation.UIThread;
import presentation.models.PostListCellRenderer;
import presentation.models.PostListModel;

import util.Log;
import util.NotFoundException;
import util.Subsystem;
import domain.user.Privilege;
import domain.user.UnpermittedActionException;


/**
 * panel for viewing a given thread content.
 * presents all its posts.
 * allows editing, adding and removing posts by permitted users.
 * @implements ListSelectionListener - in order to present post content when an item
 * from the post list is chosen
 */
public class ViewThreadPanel extends BasePanel implements ListSelectionListener
{

	private static final long serialVersionUID = -6368101448519622751L ;

	private JList postList;
	private JTextArea messageTextArea;
	private JScrollPane jScrollPane1;
	private JScrollPane jScrollPane2;
	private JSplitPane jSplitPane1;
	private JButton deletePost;
	private JButton editPost;
	private JButton addPost;
	private JLabel threadTopicLable;
	private UIThread presentedThread;
	private JTextArea authorTextArea ;
	private JScrollPane jScrollPane3 ;

	/**
	 * construct ViewThreadPanel presenting a given thread, with all its posts
	 * @param sharedData - shared data to all panels, that is created once in the MainFrame
	 * @param presentedThread - the wanted thread to present
	 * @throws RemoteException if there was a communication problem
	 * @throws NotFoundException if the root directory was not found on the server
	 * (MainFrame should catch this exceptions and notify user)
	 */
	public ViewThreadPanel(final SharedUIData sharedData, final UIThread presentedThread) throws RemoteException, NotFoundException
	{
		super(sharedData);
		this.setPreferredSize(new Dimension(735, 566));
		this.presentedThread= presentedThread;
		this.initializeGUI();
		this.refreshPresentation();
		this.makeVisible(); //to refresh the admin logging

	}

	//get all posts using this.forum and put them in the listModel
	private void refreshPresentation() throws RemoteException, NotFoundException
	{
		long threadId = this.presentedThread.getId();
		Vector<UIPost> presentedPosts = this.forum.getPosts(threadId);
		((PostListModel)this.postList.getModel()).setPosts(presentedPosts);		
		this.postList.setSelectedIndex(0);
	}

	//initialize all GUI components and hide unprivileged options when needed
	private void initializeGUI()
	{
		this.addPost = new JButton();
		this.add(this.addPost);
		this.addPost.setText("add Message");
		this.addPost.setBounds(43, 295, 122, 28);

		this.editPost = new JButton();
		this.add(this.editPost);
		this.editPost.setText("edit Message");
		this.editPost.setBounds(202, 295, 125, 28);

		this.deletePost = new JButton();
		this.add(this.deletePost);
		this.deletePost.setText("delete Message");
		this.deletePost.setBounds(363, 295, 130, 28);
		
		this.messageTextArea = new JTextArea();
		this.messageTextArea.setEditable(false);
		
		this.jScrollPane2 = new JScrollPane();
		this.jScrollPane2.setPreferredSize(new java.awt.Dimension(437, 223));
		this.jScrollPane2.setViewportView(this.messageTextArea);
		
		this.authorTextArea = new JTextArea();
		this.authorTextArea.setEditable(false);
		
		this.jScrollPane3 = new JScrollPane();
		this.jScrollPane3.setPreferredSize(new java.awt.Dimension(217, 209));
		this.jScrollPane3.setViewportView(this.authorTextArea);
		
		this.jSplitPane1 = new JSplitPane();
		this.add(this.jSplitPane1);
		this.jSplitPane1.setBounds(36, 329, 663, 225);
		this.jSplitPane1.setDividerLocation(437);
		this.jSplitPane1.add(this.jScrollPane2, JSplitPane.LEFT);
		this.jSplitPane1.add(this.jScrollPane3, JSplitPane.RIGHT);

		this.setPreferredSize(new java.awt.Dimension(735, 566));

		this.threadTopicLable = new JLabel();
		this.add(this.threadTopicLable);
		this.threadTopicLable.setText("Topic: " + this.presentedThread.getTopic());
		this.threadTopicLable.setFont(new java.awt.Font("Californian FB",1,20));
		this.threadTopicLable.setBounds(235, 56, 383, 17);
	
		ListModel postListModel = new PostListModel();
		this.postList = new JList();
		this.postList.setModel(postListModel);
		this.postList.setCellRenderer(new PostListCellRenderer(this.forum));
		this.postList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		this.postList.addListSelectionListener(this);
		this.postList.setSelectedIndex(0);
		this.postList.setBounds(30, 90, 619, 126);
		
		this.jScrollPane1 = new JScrollPane();
		this.add(this.jScrollPane1);
		this.jScrollPane1.setBounds(30, 90, 670, 157);
		this.jScrollPane1.setViewportView(this.postList);

		this.threadTopicLable.setText("Topic: "+this.presentedThread.getTopic());

		// show buttons according to user privileges
		if(!this.getSharedData().getUser().isAllowed(Privilege.ADD_POST))
		{
			this.addPost.setVisible(false);
		}

		// hide buttons when no message is selected:
		this.editPost.setVisible(false);
		this.deletePost.setVisible(false);
		
		//set button handlers:
		this.addPost.addActionListener(new java.awt.event.ActionListener() {
	         @SuppressWarnings("synthetic-access")
			public void actionPerformed(@SuppressWarnings("unused") final java.awt.event.ActionEvent evt) {
	        	ViewThreadPanel.this.addPostButtonHandler();
	         }
		 });

		this.editPost.addActionListener(new java.awt.event.ActionListener() {
	         @SuppressWarnings("synthetic-access")
			public void actionPerformed(@SuppressWarnings("unused") final java.awt.event.ActionEvent evt) {
	        	 ViewThreadPanel.this.editPostButtonHandler();
	         }
		 });

		this.deletePost.addActionListener(new java.awt.event.ActionListener() {
	         @SuppressWarnings("synthetic-access")
			public void actionPerformed(@SuppressWarnings("unused") final java.awt.event.ActionEvent evt) {
	        	 ViewThreadPanel.this.deletePostButtonHandler();
	         }
		 });
		
	}

	private void addPostButtonHandler()
	{
		// open the AddPostFrame in a new window
		AddPostFrame addPostFrame = new AddPostFrame(this);
		this.addOpenSubFrame(addPostFrame);
		addPostFrame.pack();
		addPostFrame.setVisible(true);
	}

	private void editPostButtonHandler()
	{
		// no selection was made
		if(this.postList.getSelectedIndex() == -1)
		{
			JOptionPane.showMessageDialog(ViewThreadPanel.this,
				"please choose a message to edit", "error occured", JOptionPane.ERROR_MESSAGE);
			return;
		}

		UIPost post = (UIPost)this.postList.getSelectedValue();

		//the user that's trying to edit the message is not the user that wrote the message
		if ((post.getWriterId()!=this.getSharedData().getUser().getId()
			&& !this.getSharedData().getUser().isAllowed(Privilege.EDIT_ANY_POST))
			|| (post.getWriterId()==this.getSharedData().getUser().getId()
				&& !this.getSharedData().getUser().isAllowed(Privilege.EDIT_POST))){
			JOptionPane.showMessageDialog(ViewThreadPanel.this,
				"you are not allowed to edit this message!", "error occured", JOptionPane.ERROR_MESSAGE);
		}
		else{
			// open the EditPostFrame in a new window
			EditPostFrame editPostFrame = new EditPostFrame(this,post);
			this.addOpenSubFrame(editPostFrame);
			editPostFrame.pack();
			editPostFrame.setVisible(true);
		}
				
	}

	private void deletePostButtonHandler()
	{
		//no selection was made
		if(this.postList.getSelectedIndex() == -1)
		{
			JOptionPane.showMessageDialog(ViewThreadPanel.this,
				"please choose a message to delete", "error occured", JOptionPane.ERROR_MESSAGE);
			return;
		}

		new SwingWorker<Void,Void>(){
			
			@SuppressWarnings("synthetic-access")
			@Override
			protected Void doInBackground(){	
		
				long userId = ViewThreadPanel.this.getSharedData().getUser().getId();
				long threadId = ViewThreadPanel.this.presentedThread.getId();
				UIPost post = (UIPost)ViewThreadPanel.this.postList.getSelectedValue();
		
				try
				{
					ViewThreadPanel.this.forum.deletePost(userId, post.getId(), threadId);
					((PostListModel)ViewThreadPanel.this.postList.getModel()).removeElement(post);
					JOptionPane.showMessageDialog(ViewThreadPanel.this, "message has been deleted");
					Log.getLogger(Subsystem.PRESENTATION_MODEL).finest("user " + userId + " has deleted the post "+post.getId()+" from thread "+threadId);
					ViewThreadPanel.this.messageTextArea.setText("");
				}
				catch(RemoteException e)
				{
					Log.getLogger(Subsystem.PRESENTATION_MODEL).info("could not delete message " + post.getId()) ;
					JOptionPane.showMessageDialog(ViewThreadPanel.this,
						"couldn't delete the message right now", "error occured", JOptionPane.ERROR_MESSAGE);
				}
				catch(UnpermittedActionException e)
				{
					Log.getLogger(Subsystem.PRESENTATION_MODEL).info("could not delete message " + post.getId()) ;
					JOptionPane.showMessageDialog(ViewThreadPanel.this,
						"you're not allowed to delete this message", "error occured", JOptionPane.ERROR_MESSAGE);
				}
				catch(NotFoundException e)
				{
					Log.getLogger(Subsystem.PRESENTATION_MODEL).info("could not delete message " + post.getId()) ;
					JOptionPane.showMessageDialog(ViewThreadPanel.this,
						"can't find the message", "error occured", JOptionPane.ERROR_MESSAGE);
					//try to recover by refreshing the content:
					try{
						ViewThreadPanel.this.refreshPresentation();
					}
					catch(Exception e2){
						Log.getLogger(Subsystem.PRESENTATION_MODEL).info("could not refresh presentation for thread "+ViewThreadPanel.this.presentedThread.getId()) ;
					}
				}
				return null;
			}
			@Override
			protected void done(){/*nothing to do here */}
		}.execute();
	}


	/**
	 * make this internal frame visible, and refresh it.
	 */
	@Override
	public void makeVisible(){
		try{
			this.refreshPresentation();
		}
		catch(Exception e){
			Log.getLogger(Subsystem.PRESENTATION_MODEL).info("could not refresh presentation for thread "+this.presentedThread.getId()) ;
		}
		super.makeVisible();
	}


	/**
	 * Get the present thread
	 * @return the present thread
	 */
	public UIThread getPresentThread()
	{
		return this.presentedThread ;
	}


	/**
	 * Adding a post to the forum
	 * @param message - the message content
	 * @throws RemoteException if the the communication with the server failed.
	 * @throws UnpermittedActionException if the user is unauthorized to add post.
	 * @throws NotFoundException if the user or thread do not exist.
	 */
	public void addPost(final String message) throws RemoteException, UnpermittedActionException, NotFoundException
	{
		long userId = this.getSharedData().getUser().getId();
		long threadId = this.presentedThread.getId();
		UIPost post = this.forum.addPost(threadId, userId, message);
		Log.getLogger(Subsystem.PRESENTATION_MODEL).finest("user " + userId + " has added the post "+post.getId()+" to thread "+threadId);
		((PostListModel)this.postList.getModel()).addElement(post);
		this.postList.setSelectedValue(post, true);
	}

	/**
	 * listens to the choices made in the postList, if a post is clicked on,
	 * the content of the post is presented in the lower text area
	 */
	@Override
	public void valueChanged(final ListSelectionEvent evt)
	{
		if (evt.getValueIsAdjusting())
		{
			return;
		}
		
		this.editPost.setVisible(false);
		this.deletePost.setVisible(false);
		
		if (this.postList.getSelectedIndex() != -1)
		{
			UIPost post = (UIPost)this.postList.getSelectedValue();

			// if the user is the writer of the chosen message show him the edit button
			if ( (post.getWriterId()==this.getSharedData().getUser().getId()
				&& this.getSharedData().getUser().isAllowed(Privilege.EDIT_POST))
				|| this.getSharedData().getUser().isAllowed(Privilege.EDIT_ANY_POST)){
				this.editPost.setVisible(true);
			}
			// if the user can delete posts: show this button
			if(this.getSharedData().getUser().isAllowed(Privilege.DELETE_POST))
			{
				this.deletePost.setVisible(true);
			}
			this.messageTextArea.setText(post.getMessage());
			long currMemberId = post.getWriterId();
			try
			{
				UIMember currMember = this.forum.getMemberById(currMemberId);
				String authorDetails = "Name: " + currMember.getFirstName() + " " + currMember.getLastName() + "\n";
				authorDetails = authorDetails + "Gender: " + currMember.getGender() + "\n";
				authorDetails = authorDetails + "Date of Birth: " + currMember.getDateOfBirth() + "\n";
				authorDetails = authorDetails + "Residence: " + currMember.getResidence();
				this.authorTextArea.setText(authorDetails);			
			}
			catch(NotFoundException e)
			{
				JOptionPane.showMessageDialog(ViewThreadPanel.this,
					"Something went wrong - please try again later", "error occured", JOptionPane.ERROR_MESSAGE);
				notifyCompleted();
			}
			catch(RemoteException e)
			{
				Log.getLogger(Subsystem.PRESENTATION_MODEL).info("Remote problems thrown in edit profile panel");
				JOptionPane.showMessageDialog(ViewThreadPanel.this,
					"Communication problems, please try again", "error occured", JOptionPane.ERROR_MESSAGE);
				notifyCompleted();
			}
			
		}
	}
	

	/**
	 * Edits a post in the thread
	 * @param messageText - the new content of the message
	 * @param post - the post to be edited
	 * @throws RemoteException if the the communication with the server failed.
	 * @throws UnpermittedActionException if the user is unauthorized to edit post.
	 * @throws NotFoundException if the user or post do not exist.
	 */
	public void editPost(final String messageText, final UIPost post) throws RemoteException, UnpermittedActionException, NotFoundException
	{
		long userId = this.getSharedData().getUser().getId();
		this.forum.editPost(post.getId(), userId, messageText);
		Log.getLogger(Subsystem.PRESENTATION_MODEL).finest("user " + userId + " has edited the post "+post.getId());
		try{
			this.refreshPresentation(); //so the new text will be also in the list model
		}
		catch(Exception e){
			Log.getLogger(Subsystem.PRESENTATION_MODEL).info("could not refresh presentation for thread "+this.presentedThread.getId()) ;
		}
		this.postList.setSelectedValue(post, true);
	}




}
